package org.teremail;

import java.lang.management.ManagementFactory;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServer;
import javax.sql.DataSource;

import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.h2.jdbcx.JdbcDataSource;
import org.teremail.common.Log;
import org.teremail.delivery.Exchange;
import org.teremail.delivery.ExchangeImpl;
import org.teremail.delivery.MessageHandler;
import org.teremail.delivery.MessageHandlerProvider;
import org.teremail.mailbox.DBMailboxDAO;
import org.teremail.mailbox.DBMessageDAO;
import org.teremail.mailbox.EhCacheMailboxDAOProvider;
import org.teremail.mailbox.Logical;
import org.teremail.mailbox.MailboxDAO;
import org.teremail.mailbox.MailboxService;
import org.teremail.mailbox.MailboxServiceImpl;
import org.teremail.mailbox.MessageDAO;
import org.teremail.mailbox.Physical;
import org.teremail.mailbox.search.LuceneMailboxSearch;
import org.teremail.mailbox.search.MailboxSearch;
import org.teremail.provider.DataSourceProvider;
import org.teremail.provider.DirectoryProvider;
import org.teremail.provider.ResourcePropertiesProvider;
import org.teremail.schema.Dialect;
import org.teremail.schema.H2Dialect;
import org.teremail.service.ServiceManagerMBean;
import org.teremail.service.ServiceRegistrar;
import org.teremail.service.ServiceRegistrarImpl;
import org.teremail.smtp.SMTPService;
import org.teremail.smtp.SMTPServiceProvider;
import org.teremail.store.Store;
import org.teremail.store.paged.BlobFactory;
import org.teremail.store.paged.DBBlobFactory;
import org.teremail.store.paged.PagedStore;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;

public class Main {

    private final static Log log = Log.getLog(Main.class);
    
    final static Module SMTP = new AbstractModule() {

        private Provider<Directory> luceneProvider = 
            new DirectoryProvider(new Callable<Directory>() {
            public Directory call() throws Exception {
                return FSDirectory.getDirectory("test_index");
            }
        });
        
        private Provider<DataSource> h2DataSource = 
            new DataSourceProvider(new Callable<DataSource>() {
            public DataSource call() throws Exception {
                log.debug("Initialising database");
                JdbcDataSource ds = new JdbcDataSource();
                ds.setURL("jdbc:h2:test_main/test");
                return ds;
            }
        });
        
        @Override
        protected void configure() {
            bind(Properties.class).toProvider(new ResourcePropertiesProvider("configuration.properties")).asEagerSingleton();
            bind(DataSource.class).toProvider(h2DataSource);
            bind(MessageHandler.class).toProvider(MessageHandlerProvider.class);
            bind(Dialect.class).toInstance(H2Dialect.getInstance());
            bind(BlobFactory.class).to(DBBlobFactory.class).asEagerSingleton();
            bind(Store.class).to(PagedStore.class).asEagerSingleton();
            bind(MailboxDAO.class).annotatedWith(Logical.class).toProvider(EhCacheMailboxDAOProvider.class).asEagerSingleton();
            bind(MailboxDAO.class).annotatedWith(Physical.class).to(DBMailboxDAO.class).asEagerSingleton();
            bind(MessageDAO.class).to(DBMessageDAO.class).asEagerSingleton();
            bind(MailboxService.class).to(MailboxServiceImpl.class).asEagerSingleton();
            bind(Exchange.class).to(ExchangeImpl.class).asEagerSingleton();
            bind(SMTPService.class).toProvider(SMTPServiceProvider.class).asEagerSingleton();
            bind(Directory.class).toProvider(luceneProvider);
            bind(MailboxSearch.class).to(LuceneMailboxSearch.class).asEagerSingleton();
            bind(ServiceRegistrar.class).to(ServiceRegistrarImpl.class).asEagerSingleton();
            bind(MBeanServer.class).toInstance(ManagementFactory.getPlatformMBeanServer());
        }
    };
    
    public static void main(String[] args) throws Exception {
        System.setProperty("java.util.logging.config.file", "logging.properties");
        Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).setLevel(Level.FINE);
        Injector i = Guice.createInjector(SMTP);
//        Grapher.createGraph(i);
        
        ServiceManagerMBean serviceManager = i.getInstance(ServiceRegistrar.class).createServiceManager();
        serviceManager.startAll();
        serviceManager.bindAll();
        
        serviceManager.waitForShutdown();
        
//        serviceManager.unbindAll();
//        serviceManager.stopAll();
    }
}
